<template>
  <div class="cropper-container">
    <div
        class="cropper-wrapper"
        v-for="index in getSize"
        :key="index"
    >
      <!-- 上传图片 -->
      <input
          type="file"
          @change="onFileChange(index, $event)"
          accept="image/*"
          :id="'cropper-jpeg-' + index"
      />
      <div v-show="showButton[index-1]" class="controls">
        <img
            ref="imageRefs"
            class="cropper-image"
            :id="'cropper-wrapper-' + index"
            alt="请上传图片"
        />

        <!-- 只有在 showButton[index] 为 true 时显示按钮，否则显示提示信息 -->
        <button @click="zoomIn(index)" type="button">放大</button>
        <button @click="zoomOut(index)" type="button">缩小</button>
        <button @click="rotateLeft(index)" type="button">左旋转</button>
        <button @click="rotateRight(index)" type="button">右旋转</button>
        <button @click="cropImage(index)" type="button">裁剪图片</button>
        <button @click="resetCropper(index)" type="button">重置</button>
      </div>
      <!-- 预览裁剪后的图片 -->
      <div v-if="croppedImage[index - 1]">
        <h3 class="cropped-preview-tips">裁剪结果:</h3>
        <img :src="croppedImage[index - 1]" class="cropped-preview" alt="预览图加载失败"/>
      </div>
    </div>
    <!-- 上传状态 -->
    <div v-if="uploadStatus">
      上传结果:{{ uploadStatus }}
    </div>
    <button @click="uploadCroppedImage" v-if="needUp && hasValue" type="button">提交裁剪结果</button>
  </div>
</template>

<script lang="ts" setup>
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
import {computed, nextTick, onUnmounted, ref} from 'vue'
import ResponseResult from "@models/ReturnResult.js";
import {useGlobalConfirm} from "@utils/ConfirmDialogPlugin.js";
import axiosInstance from "@utils/axiosInstance.js";
import {globalConst} from "@constants/globalConst.js";
import {getUserToken} from "@stores/localStorage.js";
import {isNull} from "@utils/stringUtil.js";
import '@assets/css/style.css'


// 接收外部参数，size默认为1，UPURl为上传路径
const props = defineProps<{
  /**
   * 需要的图片数量
   */
  size?: string;
  /**
   * 上传图片的位置(自带后端接口前缀)
   */
  UPURl?: string;
  /**
   * 图片比例
   */
  proportion?: string;
  /**
   * 图片最小宽度,小于50的会被置为50
   */
  minHeight?: string,
  /**
   * 图片最小高度,小于50的会被置为50
   */
  minWidth?: string,
  /**
   * 回调方法,将在返回成功时被调用
   * @param response
   */
  onUploadSuccess?: (response: ResponseResult<any>) => void
  /**
   * 错误时的回调方法
   */
  onUploadError?: (response: ResponseResult<any>) => void
  /**
   * 是否手动上传
   */
  OffAutomaticUpload?: boolean,
  /**
   * FormData额外参数信息
   */
  formDataMsg?: Map<string, string>,
  /**
   * 是否采用自由比例,此配置项先于自定义比例,但不影响图片大小
   */
  freeProportion?: boolean,
}>()

const getSize: number = Number.parseInt(props.size || '') || 1
const getURL: string = props.UPURl || '/user/setUserMxgOfHead'
const getProportion: number = Number.parseFloat(props.proportion || '') || 1
const needUp = !props.OffAutomaticUpload // 为空,或者false时进行上传,为true时不进行
const formDataMsg = props.formDataMsg || new Map<string, string>
let getMinWidth: number = Number(props.minWidth || '') || 100
if (getMinWidth <= 50) getMinWidth = 50

let getMinHeight: number = Number(props.minHeight || '') || 100
if (getMinHeight <= 50) getMinHeight = 50

// 存储多个 image DOM
const imageRefs = ref<(HTMLImageElement | null)[]>([])
// 存储多个 Cropper 实例，对应各个裁剪区域
const cropperInstances = ref<(Cropper | null)[]>(Array(getSize).fill(null))
// 存储各个裁剪结果
const croppedImage = ref<string[]>(Array(getSize).fill(''))
// 上传状态提示
const uploadStatus = ref<string>('')
const showButton = ref<boolean[]>(Array(getSize).fill(false))
const isUploading = ref(false)

// 计算是否有裁剪结果
const hasValue = computed(() => {
  return croppedImage.value.some(img => img !== '')
})

// 针对某个裁剪区域的文件上传
const onFileChange = (index: number, event: Event) => {
  const file = (event.target as HTMLInputElement).files?.[0]
  if (!file) return

  const reader = new FileReader()
  reader.onload = (e) => {
    if (!e.target?.result) return

    const img = new Image()
    img.onload = () => {
      // 获取图片原始宽高
      const {width, height} = img
      if (width < 50 || height < 50) {
        alert('图片长宽不能小于 50px，请选择更大的图片')
        return
      }
      let newWidth = width
      let newHeight = height
      // 拉伸小图
      if (width < 100 || height < 100) {
        const scale = Math.max(200 / width, 200 / height) // 计算缩放比例
        newWidth = Math.round(width * scale)
        newHeight = Math.round(height * scale)
      }
      // 创建 canvas 进行大小调整
      const canvas = document.createElement('canvas')
      canvas.width = newWidth
      canvas.height = newHeight
      const ctx = canvas.getContext('2d')
      if (ctx) {
        // 填充白色背景
        ctx.fillStyle = '#ffffff'
        ctx.fillRect(0, 0, newWidth, newHeight)
        // 绘制图片
        ctx.drawImage(img, 0, 0, newWidth, newHeight)
        // 生成新的 base64 图片
        const resizedImage = canvas.toDataURL('image/jpeg', 0.9)
        // 赋值到 cropper
        if (imageRefs.value[index - 1]) {
          imageRefs.value[index - 1]!.src = resizedImage
          showButton.value[index - 1] = true // 显示裁剪按钮
        }
        initCropperForIndex(index - 1) // 重新初始化裁剪器
      }
    }
    img.src = e.target.result as string
  }
  reader.readAsDataURL(file)
}
// 初始化指定区域的 Cropper 实例
const initCropperForIndex = (idx: number) => {
  // 如果已有实例，先销毁
  if (cropperInstances.value[idx]) {
    cropperInstances.value[idx]!.destroy()
    cropperInstances.value[idx] = null
  }
  // 使用 nextTick 确保 DOM 更新完毕
  nextTick(() => {
    const imageEl = imageRefs.value[idx]
    if (imageEl) {
      cropperInstances.value[idx] = new Cropper(imageEl, {
        aspectRatio: props.freeProportion ? NaN : getProportion, // 自由比例时为 NaN
        viewMode: 1,
        minCropBoxWidth: getMinWidth,
        minCropBoxHeight: getMinHeight,
        autoCropArea: 0.8,
        dragMode: 'move',
        responsive: true
      })
    }
  })
}
// 裁剪图片（将结果统一转为 JPEG），针对指定区域
const cropImage = (index: number) => {
  const idx = index - 1
  const instance = cropperInstances.value[idx]
  if (instance) {
    const canvas = instance.getCroppedCanvas()
    if (canvas) {
      // 转换为 JPEG 格式，质量 0.9
      croppedImage.value[idx] = canvas.toDataURL('image/jpeg', 0.9)
    }
  } else {
    alert('请先选择图片后在进行此操作!')
  }
}
// 重置指定区域的 Cropper
const resetCropper = (index: number) => {
  const idx = index - 1
  const instance = cropperInstances.value[idx]
  if (instance) {
    instance.reset()
  }
}

// 缩放：放大指定区域
const zoomIn = (index: number) => {
  const idx = index - 1
  const instance = cropperInstances.value[idx]
  if (instance) {
    instance.zoom(0.1)
  }
}

// 缩放：缩小指定区域
const zoomOut = (index: number) => {
  const idx = index - 1
  const instance = cropperInstances.value[idx]
  if (instance) {
    instance.zoom(-0.1)
  }
}

// 旋转：左旋指定区域
const rotateLeft = (index: number) => {
  const idx = index - 1
  const instance = cropperInstances.value[idx]
  if (instance) {
    instance.rotate(-10)
  }
}

// 旋转：右旋指定区域
const rotateRight = (index: number) => {
  const idx = index - 1
  const instance = cropperInstances.value[idx]
  if (instance) {
    instance.rotate(10)
  }
}

// 上传所有裁剪后的图片到服务器
const uploadCroppedImage = async (): Promise<{
  success: boolean;
  message: string;
  data?: any;
  response?: ResponseResult<any>;
}> => {
  isUploading.value = true

  try {
    if (needUp) {
      if (cropperInstances.value.length === 0) {
        const message = '请先选择并裁剪图片后再行提交'
        uploadStatus.value = message
        return {success: false, message}
      }

      const confirm = useGlobalConfirm()
      const r = await confirm('确定要上传图片吗?', {
        title: '是否上传当前完成裁剪的图片?',
        trueText: '确认上传',
        falseText: '取消上传'
      })

      if (!r) {
        const message = '已取消上传'
        uploadStatus.value = message
        return {success: false, message}
      }
    }

    uploadStatus.value = '准备上传...'
    const formData = new FormData()
    const processedBlobs: Blob[] = [] // 存放有效裁剪的 Blob

    // 使用 for 循环逐步处理裁剪图片
    for (let i = 0; i < cropperInstances.value.length; i++) {
      if (!croppedImage.value[i]) continue // 确保已经裁剪过
      const base64String = croppedImage.value[i]
      // 将 Base64 转换为 Blob
      const byteString = atob(base64String.split(',')[1])
      const mimeString = base64String.split(',')[0].split(':')[1].split(';')[0]
      const arrayBuffer = new ArrayBuffer(byteString.length)
      const uintArray = new Uint8Array(arrayBuffer)
      for (let j = 0; j < byteString.length; j++) {
        uintArray[j] = byteString.charCodeAt(j)
      }
      const blob = new Blob([arrayBuffer], {type: mimeString})
      processedBlobs.push(blob)
    }
    if (processedBlobs.length === 0 && needUp) {
      const message = '错误! 没有获取到任何裁剪结果!'
      uploadStatus.value = message
      alert(message)
      return {success: false, message}
    }
    if (processedBlobs.length === 0 && !needUp) {
      const confirm = useGlobalConfirm()
      const b = await confirm('您当前没有选择任何图片,确定要继续吗?\n如果您选择了图片请先进行裁剪操作', {
        trueText: '是的',
        falseText: '返回'
      });
      return {
        success: b,
        message: b ? '用户确认继续' : '用户取消操作'
      }
    }
    // 仅上传有效的裁剪结果
    if (getSize === 1) {
      formData.append('croppedImage', processedBlobs[0])
    } else {
      let fileSize = 0
      processedBlobs.forEach((blob) => {
        formData.append(`fileList`, blob)
        fileSize++
      })
      formData.append('fileSize', String(fileSize))
    }
    if (!isNull(formDataMsg)) {
      for (let [key, value] of formDataMsg) {
        console.log("key:", key)
        console.log("value:", value)
        formData.append(key, value)
      }
    }
    // 发送请求
    const response = await axiosInstance.post(getURL, formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
        [globalConst.tokenName]: getUserToken()
      }
    })
    const r1 = ResponseResult.fromApiResponse(response.data)
    uploadStatus.value = String(r1.msg)
    if (r1.isSuccess()) {
      if (typeof props.onUploadSuccess === 'function') {
        props.onUploadSuccess(r1)
      }
      resetAll() // 清空所有结果
      return {
        success: true,
        message: String(r1.msg),
        data: r1.returnResult,
        response: r1
      }
    } else {
      if (typeof props.onUploadError === 'function') {
        props.onUploadError(r1)
      }
      alert('图片上传失败!具体信息:' + r1.msg)
      return {
        success: false,
        message: String(r1.msg),
        data: r1.returnResult,
        response: r1
      }
    }
  } catch (error: any) {
    const message = `上传失败: ${error.message || '未知错误'}`
    uploadStatus.value = message
    console.error('上传失败', error)
    return {success: false, message}
  } finally {
    isUploading.value = false
  }
}

// 获取当前裁剪的图片数据
const getCroppedImages = (): string[] => {
  return croppedImage.value.filter(img => img !== '')
}

// 获取裁剪图片数量
const getCroppedCount = (): number => {
  return croppedImage.value.filter(img => img !== '').length
}

// 检查是否所有图片都已裁剪
const isAllCropped = (): boolean => {
  return croppedImage.value.every(img => img !== '')
}

// 重置所有裁剪区域，包括 Cropper 实例、图片预览、输入框
const resetAll = () => {
  // 销毁所有 cropper 实例
  cropperInstances.value.forEach((instance, idx) => {
    if (instance) instance.destroy()
    cropperInstances.value[idx] = null
  })

  // 清空裁剪结果
  croppedImage.value = Array(getSize).fill('')

  // 隐藏控制按钮
  showButton.value = Array(getSize).fill(false)

  // 清空图片 src
  imageRefs.value.forEach((img) => {
    if (img) img.src = ''
  })

  // 清空上传状态
  uploadStatus.value = ''
}

// 组件销毁时，依次销毁所有 Cropper 实例
onUnmounted(() => {
  cropperInstances.value.forEach((instance) => {
    if (instance) instance.destroy()
  })
})

// 对外暴露的方法
defineExpose({
  uploadCroppedImage,
  getCroppedImages,
  getCroppedCount,
  isAllCropped,
  resetAll,
  cropAll: () => {
    for (let i = 1; i <= getSize; i++) {
      cropImage(i)
    }
  },
  getUploadStatus: () => uploadStatus.value,
  isUploading: () => isUploading.value
})
</script>

<style scoped>
/* 图片裁剪容器 - 保持原有布局，仅适配主题 */
.cropper-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  padding: 20px;
  background: rgba(42, 42, 42, 0.8); /* 深色背景但保持足够对比度 */
  border-radius: 16px;
  border: 1px solid rgba(255, 42, 109, 0.3);
  box-shadow: 0 8px 30px rgba(255, 42, 109, 0.15);
  max-width: 800px;
  margin: 0 auto;
}

/* 单个裁剪包装器 - 保持原有结构 */
.cropper-wrapper {
  border: 1px solid var(--border-secondary);
  padding: 15px;
  margin-bottom: 20px;
  width: 100%;
  max-width: 400px;
  background: rgba(26, 26, 26, 0.7);
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  transition: box-shadow 0.3s ease;
}

.cropper-wrapper:hover {
  box-shadow: 0 6px 20px rgba(255, 42, 109, 0.2);
}

/* 裁剪图片 - 保持原有样式 */
.cropper-image {
  width: 100%;
  display: block;
  border: 1px solid var(--border-secondary);
  border-radius: 8px;
  margin-bottom: 10px;
  max-height: 300px;
  object-fit: contain;
  background: var(--bg-secondary);
}

/* 控制按钮容器 - 保持原有布局 */
.controls {
  margin-top: 10px;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}

/* 控制按钮 - 保持原有功能，仅更新颜色 */
.controls button {
  padding: 8px 12px;
  border: none;
  background: linear-gradient(135deg, var(--primary-red), var(--primary-purple));
  color: var(--text-primary);
  cursor: pointer;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.3s ease;
  box-shadow: 0 2px 8px rgba(255, 42, 109, 0.3);
}

.controls button:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(255, 42, 109, 0.4);
}

.controls button:active {
  transform: translateY(0);
}

.controls button:disabled {
  background: var(--secondary-gray);
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* 裁剪预览 */
.cropped-preview {
  margin-top: 10px;
  max-width: 100%;
  border: 1px solid var(--border-secondary);
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  background: var(--bg-secondary);
}

/* 文件选择框 - 轻微适配，保持可用性 */
input[type="file"] {
  margin-bottom: 10px;
  font-size: 14px;
  padding: 8px;
  border: 1px solid var(--border-secondary);
  border-radius: 8px;
  background: var(--bg-secondary);
  color: var(--text-primary);
  cursor: pointer;
  transition: border-color 0.3s ease;
  width: 100%;
}

input[type="file"]:hover {
  border-color: var(--primary-purple);
}

/* 提示文本 */
.cropped-preview-tips {
  font-size: 14px;
  color: var(--text-secondary);
  text-align: center;
  margin: 10px 0;
  padding: 10px;
  background: rgba(26, 26, 26, 0.5);
  border-radius: 8px;
  border: 1px solid var(--border-secondary);
}

/* 上传状态 */
.upload-status {
  color: var(--text-secondary);
  font-size: 14px;
  padding: 10px;
  background: rgba(42, 42, 42, 0.6);
  border-radius: 8px;
  border: 1px solid var(--border-secondary);
  margin: 10px 0;
}

/* 提交按钮 */
.cropper-container > button {
  padding: 10px 20px;
  border: none;
  background: linear-gradient(135deg, var(--primary-red), var(--primary-purple));
  color: var(--text-primary);
  cursor: pointer;
  border-radius: 8px;
  font-size: 16px;
  font-weight: 600;
  transition: all 0.3s ease;
  box-shadow: 0 4px 12px rgba(255, 42, 109, 0.3);
  margin-top: 10px;
}

.cropper-container > button:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(255, 42, 109, 0.4);
}

.cropper-container > button:active {
  transform: translateY(0);
}

/* 响应式设计 - 保持原有响应式逻辑 */
@media (max-width: 600px) {
  .cropper-container {
    padding: 15px;
  }

  .cropper-wrapper {
    padding: 10px;
  }

  .controls {
    gap: 8px;
  }

  .controls button {
    padding: 6px 10px;
    font-size: 12px;
    flex: 1 1 45%;
  }
}
</style>
